package com.tupu.service.impl.admin;

import cn.hutool.http.server.HttpServerResponse;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tupu.entity.admin.*;
import com.tupu.entity.neo4j.NodeSingle;
import com.tupu.entity.neo4j.RelationListAll;
import com.tupu.mapper.admin.*;
import com.tupu.service.admin.KnowledgeListService;
import com.tupu.util.FileUtil;
import com.tupu.util.Neo4jUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.*;

@Slf4j
@Service
public class KnowledgeListServiceImpl extends ServiceImpl<KnowledgeListMapper, KnowledgeInfo> implements KnowledgeListService {

    @Autowired(required = false)
    private KnowledgeListMapper knowledgeListMapper;

    @Autowired(required = false)
    private LabelMapper labelMapper;

    @Autowired(required = false)
    private PropertyMapper propertyMapper;

    @Autowired(required = false)
    private RelationMapper relationMapper;

    @Autowired(required = false)
    private RelationBuildingMapper relationBuildingMapper;

    @Autowired(required = false)
    private Neo4jUtil neo4jUtil;

    //ip地址
    @Value("${file.ipAddress}")
    private String ipAddress;

    /**
     * 图谱首页、分页、模糊查询
     *
     * @param name
     * @param page
     * @param size
     * @return
     */
    @Override
    public Page<KnowledgeInfo> pageInfo(String name, Long page, Long size) {
        QueryWrapper<KnowledgeInfo> queryWrapper = new QueryWrapper<>();
        Page<KnowledgeInfo> pageInfo = new Page<>(page, size);
        if (StringUtils.isNotEmpty(name)) {
            queryWrapper.like("name", name);
        }
        queryWrapper.orderByDesc("id");
        knowledgeListMapper.selectPage(pageInfo, queryWrapper);
        //更改图片返回url 拼接ip地址(改为输出流)
        List<KnowledgeInfo> records = pageInfo.getRecords();
        for (KnowledgeInfo knowledge : records) {
            //读取图片文件
            String path = knowledge.getImages();
            Path imagePath = Paths.get(path);
            byte[] imageBytes = new byte[1024];
            try {
                imageBytes = Files.readAllBytes(imagePath);
            } catch (IOException e) {
                e.printStackTrace();
            }
            //将图片数据进行Base64编码
            String imageData = Base64.getEncoder().encodeToString(imageBytes);
            knowledge.setImages(imageData);
            // knowledge.setImages(ipAddress + knowledge.getImages());
        }
        return pageInfo;
    }

    /**
     * 图谱列表 不分页
     *
     * @return
     */
    @Override
    public List<KnowledgeInfo> listAll() {
        List<KnowledgeInfo> knowledgeInfos = knowledgeListMapper.selectList(null);
        for (KnowledgeInfo knowledge : knowledgeInfos) {
            knowledge.setImages(ipAddress + knowledge.getImages());
        }
        return knowledgeInfos;
    }

    /**
     * 新建图谱
     *
     * @param knowledgeInfo
     */
    @Override
    public void addKnowledge(KnowledgeInfo knowledgeInfo) {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String format = sdf.format(date);
        knowledgeInfo.setCreatedTime(format);
        knowledgeListMapper.insert(knowledgeInfo);
    }

    /**
     * 编辑图谱
     *
     * @param knowledgeInfo
     */
    @Override
    public void updateKnowledge(KnowledgeInfo knowledgeInfo) {
        //更新日期
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String format = sdf.format(date);

        knowledgeInfo.setId(knowledgeInfo.getId());
        knowledgeInfo.setImages(knowledgeInfo.getImages());
        knowledgeInfo.setDetails(knowledgeInfo.getDetails());
        knowledgeInfo.setName(knowledgeInfo.getName());
        knowledgeInfo.setCreatedTime(format);
        knowledgeListMapper.updateById(knowledgeInfo);
    }

    /**
     * 图谱备份
     *
     * @param node_id
     * @return
     */
    @Override
    public Map<String, Object> backup(Integer node_id, HttpServerResponse response) throws IOException {
        //文件名称
        Map<String, Object> result = new HashMap<>();
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < 6; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        String format = sdf.format(date);
        String name = format + "_" + sb.toString();
        //新建工作表
        XSSFWorkbook workbook = new XSSFWorkbook();
        //设置格式
        XSSFCellStyle style = workbook.createCellStyle();
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        //sheet1 标签表
        XSSFSheet sheet1 = workbook.createSheet("标签");
        XSSFRow row0 = sheet1.createRow(0);
        row0.createCell(0).setCellValue("Name");
        row0.createCell(1).setCellValue("Property");

        QueryWrapper<LabelInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("node_id", node_id);
        List<LabelInfo> labelLists = labelMapper.selectList(queryWrapper);
        //获取属性最大值
        /*List<Integer> propertyList = new ArrayList<>();
        for (LabelList label : labelLists) {
            Long labelId = label.getId();
            QueryWrapper<PropertyList> propertywrapper = new QueryWrapper<>();
            propertywrapper.eq("label_id", labelId);
            List<PropertyList> propertyLists = propertyMapper.selectList(propertywrapper);
            int propertySize = propertyLists.size();
            propertyList.add(propertySize);
        }
        Integer propertyMax = Collections.max(propertyList);
        System.out.println("属性个数：" + propertyMax);
        for (int i = 1; i < propertyMax + 1; i++) {
            row0.createCell(i).setCellValue("Property" + i);
        }*/
        //插入标签数据
        List<String> propertyLists = null;
        for (int i = 0; i < labelLists.size(); i++) {
            propertyLists = new ArrayList<>();
            XSSFRow row = sheet1.createRow(i + 1);
            String label = labelLists.get(i).getLabel();
            Long labelId = labelLists.get(i).getId();
            //根据id 生成属性集合
            row.createCell(0).setCellValue(label);
            QueryWrapper<LabelPropertyInfo> propertyWrapper = new QueryWrapper<>();
            propertyWrapper.eq("label_id", labelId);
            List<LabelPropertyInfo> labelPropertyListInfo = propertyMapper.selectList(propertyWrapper);
            for (LabelPropertyInfo pro : labelPropertyListInfo) {
                propertyLists.add(pro.getName());
            }
            row.createCell(1).setCellValue(StringUtils.join(propertyLists, ";"));
        }

        //sheet2 标签关系表
        XSSFSheet sheet2 = workbook.createSheet("关系");
        XSSFRow row2 = sheet2.createRow(0);
        row2.createCell(0).setCellValue(":START_LABEL");
        row2.createCell(1).setCellValue(":END_LABEL");
        row2.createCell(2).setCellValue(":RelationShip");
        QueryWrapper<RelationBuildingInfo> queryWrapper1 = new QueryWrapper<>();
        queryWrapper1.eq("node_id", node_id);
        List<RelationBuildingInfo> labelRelationLists = relationBuildingMapper.selectList(queryWrapper1);
        //插入标签关系数据
        for (int i = 0; i < labelRelationLists.size(); i++) {
            XSSFRow row = sheet2.createRow(i + 1);
            Long startId = labelRelationLists.get(i).getStartId();
            Long endId = labelRelationLists.get(i).getEndId();
            Long relationId = labelRelationLists.get(i).getRelationId();
            String startLabel = labelMapper.selectById(startId).getLabel();
            String endLabel = labelMapper.selectById(endId).getLabel();
            String relation = relationMapper.selectById(relationId).getName();
            row.createCell(0).setCellValue(startLabel);
            row.createCell(1).setCellValue(endLabel);
            row.createCell(2).setCellValue(relation);
        }

        //sheet3,实例数据
        List<NodeSingle> nodes = neo4jUtil.findNodeByNodeId(Long.valueOf(node_id));
        XSSFSheet sheet3 = workbook.createSheet("实例");
        XSSFRow row4 = sheet3.createRow(0);
        row4.createCell(0).setCellValue("name");
        row4.createCell(1).setCellValue(":LABEL");
        row4.createCell(2).setCellValue("uid");
        row4.createCell(3).setCellValue("属性");
        row4.createCell(4).setCellValue("属性值");
        for (int j = 0; j < nodes.size(); j++) {
            XSSFRow row = sheet3.createRow(j + 1);
            //通过实例id查询label、
            Long id = nodes.get(j).getId();
            String label = neo4jUtil.findByCaseId(id);
            Map<String, Object> attrs = nodes.get(j).getAttrs();

            List<String> keys = new ArrayList<>();
            List<String> values = new ArrayList<>();

            for (String key : attrs.keySet()) {
                keys.add(key);
                values.add(String.valueOf(attrs.get(key)));
                if (key.equals("uid")) {
                    String value = (String) attrs.get(key);
                    row.createCell(2).setCellValue(value);
                }

                keys.remove("node_id");
                values.remove(String.valueOf(attrs.get("node_id")));
            }

            row.createCell(0).setCellValue(neo4jUtil.findNameById(id));
            row.createCell(1).setCellValue(label);

            row.createCell(3).setCellValue(StringUtils.join(keys, ","));
            row.createCell(4).setCellValue(StringUtils.join(values, ","));
        }

        //sheet4 实例关系表
        XSSFSheet sheet4 = workbook.createSheet("实例关系");
        XSSFRow row3 = sheet4.createRow(0);
        row3.createCell(0).setCellValue("START_ID");
        row3.createCell(1).setCellValue("END_ID");
        row3.createCell(2).setCellValue("TYPE");
        List<RelationListAll> relationListAlls = neo4jUtil.findAllRelationByNodeId(Long.valueOf(node_id));
        for (RelationListAll rela : relationListAlls) {
            String startName = neo4jUtil.findNameById(rela.getStartId());
            rela.setStartName(startName);
            String endName = neo4jUtil.findNameById(rela.getEndId());
            rela.setEndName(endName);
        }
        for (int i = 0; i < relationListAlls.size(); i++) {
            XSSFRow row = sheet4.createRow(i + 1);
            String startName = relationListAlls.get(i).getStartName();
            String endName = relationListAlls.get(i).getEndName();
            String type = relationListAlls.get(i).getType();
            row.createCell(0).setCellValue(startName);
            row.createCell(1).setCellValue(endName);
            row.createCell(2).setCellValue(type);
        }
        String path = "/home/csv/" + name + ".xlsx";
        workbook.write(new FileOutputStream(path));

        FileUtil.download(path, (HttpServletResponse) response);
        return result;
    }

    /**
     * 上传图片
     *
     * @param file
     * @return
     */
    @Override
    public Map<String, Object> uploadPicture(MultipartFile file) throws IOException {
        Map<String, Object> result = new HashMap<>();
        //获取文件的名字
        String originName = file.getOriginalFilename();
        log.info("originName:" + originName);
        //判断文件类型
        if (!originName.endsWith(".jpg") && !originName.endsWith(".png") && !originName.endsWith(".jpeg")) {
            result.put("status", "error");
            result.put("msg", "文件类型不对");
            return result;
        }
        //给上传文件取新的名字+原后缀，避免重名
        String ext = originName.substring(originName.lastIndexOf("."));
        String newName = UUID.randomUUID().toString() + ext;
        // 上传图片到指定文件夹（想存放地址的相对路径）
        File savePos = new File("/home/images/");
        /*//给上传的文件新建目录
        String format = sdf.format(new Date());
        String realPath = fileSavePath + format;
        System.out.println("realPath:" + realPath);
                File folder = new File(realPath);*/
        // 若目录不存在则创建目录、创建该文件夹
        if (!savePos.exists()) {
            savePos.mkdir();
        }
        // 获取存放位置的规范路径
        String realPath = savePos.getCanonicalPath();
        // 上传该文件/图像至该文件夹下
        file.transferTo(new File(realPath + "/" + newName));
        //获得本机Ip（获取的是服务器的Ip）
        //InetAddress inetAddress = InetAddress.getLocalHost();
        //String ip = inetAddress.getHostAddress();
        //返回保存的url，根据url可以进行图片查看
        String fileDownloadUrl = "/home/images/" + newName;
        //log.info(fileDownloadUrl);
        //输出结果
        result.put("status", "success");
        result.put("url", fileDownloadUrl);
        return result;
    }

    /**
     * 根据id查找一个图谱
     *
     * @param id
     */
    @Override
    public KnowledgeInfo findById(Integer id) {
        KnowledgeInfo info = knowledgeListMapper.selectById(id);
        //读取图片文件
        String path = info.getImages();
        Path imagePath = Paths.get(path);
        byte[] imageBytes = new byte[1024];
        try {
            imageBytes = Files.readAllBytes(imagePath);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //将图片数据进行Base64编码
        String imageData = Base64.getEncoder().encodeToString(imageBytes);
        info.setImages(imageData);
        return info;
    }

    /**
     * 删除当前图谱下的所有（实例、标签、关系）
     *
     * @param node_id
     */
    @Override
    public void deleteByNodeId(Integer node_id) {
        //删除图谱首页
        knowledgeListMapper.deleteById(node_id);
        QueryWrapper<LabelInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("node_id", node_id);
        //删除属性
        List<LabelInfo> labelLists = labelMapper.selectList(queryWrapper);
        for (LabelInfo labelList : labelLists) {
            propertyMapper.deleteByLabelId(labelList.getId());
        }
        //删除实体标签
        labelMapper.delete(queryWrapper);
        //删除关系表
        QueryWrapper<RelationInfo> queryWrapper3 = new QueryWrapper<>();
        queryWrapper3.eq("node_id", node_id);
        relationMapper.delete(queryWrapper3);
        //删除关系关联表数据
        QueryWrapper<RelationBuildingInfo> queryWrapper2 = new QueryWrapper<>();
        queryWrapper2.eq("node_id", node_id);
        relationBuildingMapper.delete(queryWrapper2);
        //删除图谱id下所有
        neo4jUtil.delAllByNodeId(Long.valueOf(node_id));
    }

}
